package eval

import (
	"showen/num"
	"showen/obj"
)

// SetCar modifies the car field of a pair
func SetCar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 2 {
		return &Error{Message: "set-car! requires exactly 2 arguments"}
	}

	// First argument must be a pair
	pair, ok := args[0].(*obj.PairObject)
	if !ok {
		return &Error{Message: "set-car! first argument must be a pair"}
	}

	// Set the car field to the second argument
	pair.Car = args[1]

	// set-car! returns an unspecified value, we'll use NULL_OBJECT
	return obj.NULL_OBJECT
}

// SetCdr modifies the cdr field of a pair
func SetCdr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 2 {
		return &Error{Message: "set-cdr! requires exactly 2 arguments"}
	}

	// First argument must be a pair
	pair, ok := args[0].(*obj.PairObject)
	if !ok {
		return &Error{Message: "set-cdr! first argument must be a pair"}
	}

	// Set the cdr field to the second argument
	pair.Cdr = args[1]

	// set-cdr! returns an unspecified value, we'll use NULL_OBJECT
	return obj.NULL_OBJECT
}

// Caar returns the car of the car of a pair
func Caar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "caar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "caar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "caar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caar: car of argument is not a pair"}
	}

	return convertToObjObject(carPair.Car)
}

// Cadr returns the car of the cdr of a pair
func Cadr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cadr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cadr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "cadr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadr: cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrPair.Car)
}

// Cdar returns the cdr of the car of a pair
func Cdar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cdar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cdar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "cdar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdar: car of argument is not a pair"}
	}

	return convertToObjObject(carPair.Cdr)
}

// Cddr returns the cdr of the cdr of a pair
func Cddr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cddr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cddr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "cddr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddr: cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrPair.Cdr)
}

// Caaar returns the car of the car of the car of a pair
func Caaar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "caaar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "caaar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "caaar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caaar: car of argument is not a pair"}
	}

	if carPair.Car == nil {
		return &Error{Message: "caaar: car of car of argument is nil"}
	}

	carCarPair, ok := carPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caaar: car of car of argument is not a pair"}
	}

	return convertToObjObject(carCarPair.Car)
}

// Caadr returns the car of the car of the cdr of a pair
func Caadr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "caadr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "caadr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "caadr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caadr: cdr of argument is not a pair"}
	}

	if cdrPair.Car == nil {
		return &Error{Message: "caadr: car of cdr of argument is nil"}
	}

	cdrCarPair, ok := cdrPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caadr: car of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCarPair.Car)
}

// Cadar returns the car of the cdr of the car of a pair
func Cadar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cadar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cadar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "cadar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadar: car of argument is not a pair"}
	}

	if carPair.Cdr == nil {
		return &Error{Message: "cadar: cdr of car of argument is nil"}
	}

	carCdrPair, ok := carPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadar: cdr of car of argument is not a pair"}
	}

	return convertToObjObject(carCdrPair.Car)
}

// Caddr returns the car of the cdr of the cdr of a pair
func Caddr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "caddr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "caddr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "caddr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caddr: cdr of argument is not a pair"}
	}

	if cdrPair.Cdr == nil {
		return &Error{Message: "caddr: cdr of cdr of argument is nil"}
	}

	cdrCdrPair, ok := cdrPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caddr: cdr of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCdrPair.Car)
}

// Cdaar returns the cdr of the car of the car of a pair
func Cdaar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cdaar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cdaar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "cdaar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdaar: car of argument is not a pair"}
	}

	if carPair.Car == nil {
		return &Error{Message: "cdaar: car of car of argument is nil"}
	}

	carCarPair, ok := carPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdaar: car of car of argument is not a pair"}
	}

	return convertToObjObject(carCarPair.Cdr)
}

// Cdadr returns the cdr of the car of the cdr of a pair
func Cdadr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cdadr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cdadr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "cdadr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdadr: cdr of argument is not a pair"}
	}

	if cdrPair.Car == nil {
		return &Error{Message: "cdadr: car of cdr of argument is nil"}
	}

	cdrCarPair, ok := cdrPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdadr: car of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCarPair.Cdr)
}

// Cddar returns the cdr of the cdr of the car of a pair
func Cddar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cddar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cddar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "cddar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddar: car of argument is not a pair"}
	}

	if carPair.Cdr == nil {
		return &Error{Message: "cddar: cdr of car of argument is nil"}
	}

	carCdrPair, ok := carPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddar: cdr of car of argument is not a pair"}
	}

	return convertToObjObject(carCdrPair.Cdr)
}

// Cdddr returns the cdr of the cdr of the cdr of a pair
func Cdddr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cdddr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cdddr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "cdddr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdddr: cdr of argument is not a pair"}
	}

	if cdrPair.Cdr == nil {
		return &Error{Message: "cdddr: cdr of cdr of argument is nil"}
	}

	cdrCdrPair, ok := cdrPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdddr: cdr of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCdrPair.Cdr)
}

// Caaaar returns the car of the car of the car of the car of a pair
func Caaaar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "caaaar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "caaaar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "caaaar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caaaar: car of argument is not a pair"}
	}

	if carPair.Car == nil {
		return &Error{Message: "caaaar: car of car of argument is nil"}
	}

	carCarPair, ok := carPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caaaar: car of car of argument is not a pair"}
	}

	if carCarPair.Car == nil {
		return &Error{Message: "caaaar: car of car of car of argument is nil"}
	}

	carCarCarPair, ok := carCarPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caaaar: car of car of car of argument is not a pair"}
	}

	return convertToObjObject(carCarCarPair.Car)
}

// Caaadr returns the car of the car of the car of the cdr of a pair
func Caaadr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "caaadr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "caaadr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "caaadr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caaadr: cdr of argument is not a pair"}
	}

	if cdrPair.Car == nil {
		return &Error{Message: "caaadr: car of cdr of argument is nil"}
	}

	cdrCarPair, ok := cdrPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caaadr: car of cdr of argument is not a pair"}
	}

	if cdrCarPair.Car == nil {
		return &Error{Message: "caaadr: car of car of cdr of argument is nil"}
	}

	cdrCarCarPair, ok := cdrCarPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caaadr: car of car of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCarCarPair.Car)
}

// Caadar returns the car of the cdr of the car of the car of a pair
func Caadar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "caadar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "caadar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "caadar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caadar: car of argument is not a pair"}
	}

	if carPair.Cdr == nil {
		return &Error{Message: "caadar: cdr of car of argument is nil"}
	}

	carCdrPair, ok := carPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caadar: cdr of car of argument is not a pair"}
	}

	if carCdrPair.Car == nil {
		return &Error{Message: "caadar: car of cdr of car of argument is nil"}
	}

	carCdrCarPair, ok := carCdrPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caadar: car of cdr of car of argument is not a pair"}
	}

	return convertToObjObject(carCdrCarPair.Car)
}

// Caaddr returns the car of the car of the cdr of the cdr of a pair
func Caaddr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "caaddr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "caaddr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "caaddr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caaddr: cdr of argument is not a pair"}
	}

	if cdrPair.Cdr == nil {
		return &Error{Message: "caaddr: cdr of cdr of argument is nil"}
	}

	cdrCdrPair, ok := cdrPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caaddr: cdr of cdr of argument is not a pair"}
	}

	if cdrCdrPair.Car == nil {
		return &Error{Message: "caaddr: car of cdr of cdr of argument is nil"}
	}

	cdrCdrCarPair, ok := cdrCdrPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caaddr: car of cdr of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCdrCarPair.Car)
}

// Cadaar returns the car of the cdr of the car of the car of a pair
func Cadaar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cadaar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cadaar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "cadaar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadaar: car of argument is not a pair"}
	}

	if carPair.Car == nil {
		return &Error{Message: "cadaar: car of car of argument is nil"}
	}

	carCarPair, ok := carPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadaar: car of car of argument is not a pair"}
	}

	if carCarPair.Cdr == nil {
		return &Error{Message: "cadaar: cdr of car of car of argument is nil"}
	}

	carCarCdrPair, ok := carCarPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadaar: cdr of car of car of argument is not a pair"}
	}

	return convertToObjObject(carCarCdrPair.Car)
}

// Cadadr returns the car of the cdr of the car of the cdr of a pair
func Cadadr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cadadr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cadadr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "cadadr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadadr: cdr of argument is not a pair"}
	}

	if cdrPair.Car == nil {
		return &Error{Message: "cadadr: car of cdr of argument is nil"}
	}

	cdrCarPair, ok := cdrPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadadr: car of cdr of argument is not a pair"}
	}

	if cdrCarPair.Cdr == nil {
		return &Error{Message: "cadadr: cdr of car of cdr of argument is nil"}
	}

	cdrCarCdrPair, ok := cdrCarPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadadr: cdr of car of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCarCdrPair.Car)
}

// Caddar returns the car of the cdr of the cdr of the car of a pair
func Caddar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "caddar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "caddar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "caddar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caddar: car of argument is not a pair"}
	}

	if carPair.Cdr == nil {
		return &Error{Message: "caddar: cdr of car of argument is nil"}
	}

	carCdrPair, ok := carPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caddar: cdr of car of argument is not a pair"}
	}

	if carCdrPair.Cdr == nil {
		return &Error{Message: "caddar: cdr of cdr of car of argument is nil"}
	}

	carCdrCdrPair, ok := carCdrPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "caddar: cdr of cdr of car of argument is not a pair"}
	}

	return convertToObjObject(carCdrCdrPair.Car)
}

// Cadddr returns the car of the cdr of the cdr of the cdr of a pair
func Cadddr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cadddr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cadddr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "cadddr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadddr: cdr of argument is not a pair"}
	}

	if cdrPair.Cdr == nil {
		return &Error{Message: "cadddr: cdr of cdr of argument is nil"}
	}

	cdrCdrPair, ok := cdrPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadddr: cdr of cdr of argument is not a pair"}
	}

	if cdrCdrPair.Cdr == nil {
		return &Error{Message: "cadddr: cdr of cdr of cdr of argument is nil"}
	}

	cdrCdrCdrPair, ok := cdrCdrPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cadddr: cdr of cdr of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCdrCdrPair.Car)
}

// Cdaaar returns the cdr of the car of the car of the car of a pair
func Cdaaar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cdaaar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cdaaar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "cdaaar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdaaar: car of argument is not a pair"}
	}

	if carPair.Car == nil {
		return &Error{Message: "cdaaar: car of car of argument is nil"}
	}

	carCarPair, ok := carPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdaaar: car of car of argument is not a pair"}
	}

	if carCarPair.Car == nil {
		return &Error{Message: "cdaaar: car of car of car of argument is nil"}
	}

	carCarCarPair, ok := carCarPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdaaar: car of car of car of argument is not a pair"}
	}

	return convertToObjObject(carCarCarPair.Cdr)
}

// Cdaadr returns the cdr of the car of the car of the cdr of a pair
func Cdaadr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cdaadr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cdaadr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "cdaadr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdaadr: cdr of argument is not a pair"}
	}

	if cdrPair.Car == nil {
		return &Error{Message: "cdaadr: car of cdr of argument is nil"}
	}

	cdrCarPair, ok := cdrPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdaadr: car of cdr of argument is not a pair"}
	}

	if cdrCarPair.Car == nil {
		return &Error{Message: "cdaadr: car of car of cdr of argument is nil"}
	}

	cdrCarCarPair, ok := cdrCarPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdaadr: car of car of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCarCarPair.Cdr)
}

// Cdadar returns the cdr of the car of the cdr of the car of a pair
func Cdadar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cdadar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cdadar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "cdadar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdadar: car of argument is not a pair"}
	}

	if carPair.Cdr == nil {
		return &Error{Message: "cdadar: cdr of car of argument is nil"}
	}

	carCdrPair, ok := carPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdadar: cdr of car of argument is not a pair"}
	}

	if carCdrPair.Car == nil {
		return &Error{Message: "cdadar: car of cdr of car of argument is nil"}
	}

	carCdrCarPair, ok := carCdrPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdadar: car of cdr of car of argument is not a pair"}
	}

	return convertToObjObject(carCdrCarPair.Cdr)
}

// Cdaddr returns the cdr of the car of the cdr of the cdr of a pair
func Cdaddr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cdaddr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cdaddr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "cdaddr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdaddr: cdr of argument is not a pair"}
	}

	if cdrPair.Cdr == nil {
		return &Error{Message: "cdaddr: cdr of cdr of argument is nil"}
	}

	cdrCdrPair, ok := cdrPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdaddr: cdr of cdr of argument is not a pair"}
	}

	if cdrCdrPair.Car == nil {
		return &Error{Message: "cdaddr: car of cdr of cdr of argument is nil"}
	}

	cdrCdrCarPair, ok := cdrCdrPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdaddr: car of cdr of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCdrCarPair.Cdr)
}

// Cddaar returns the cdr of the cdr of the car of the car of a pair
func Cddaar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cddaar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cddaar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "cddaar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddaar: car of argument is not a pair"}
	}

	if carPair.Car == nil {
		return &Error{Message: "cddaar: car of car of argument is nil"}
	}

	carCarPair, ok := carPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddaar: car of car of argument is not a pair"}
	}

	if carCarPair.Cdr == nil {
		return &Error{Message: "cddaar: cdr of car of car of argument is nil"}
	}

	carCarCdrPair, ok := carCarPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddaar: cdr of car of car of argument is not a pair"}
	}

	return convertToObjObject(carCarCdrPair.Cdr)
}

// Cddadr returns the cdr of the cdr of the car of the cdr of a pair
func Cddadr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cddadr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cddadr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "cddadr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddadr: cdr of argument is not a pair"}
	}

	if cdrPair.Car == nil {
		return &Error{Message: "cddadr: car of cdr of argument is nil"}
	}

	cdrCarPair, ok := cdrPair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddadr: car of cdr of argument is not a pair"}
	}

	if cdrCarPair.Cdr == nil {
		return &Error{Message: "cddadr: cdr of car of cdr of argument is nil"}
	}

	cdrCarCdrPair, ok := cdrCarPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddadr: cdr of car of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCarCdrPair.Cdr)
}

// Cdddar returns the cdr of the cdr of the cdr of the car of a pair
func Cdddar(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cdddar requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cdddar argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Car == nil {
		return &Error{Message: "cdddar: car of argument is nil"}
	}

	carPair, ok := pair.Car.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdddar: car of argument is not a pair"}
	}

	if carPair.Cdr == nil {
		return &Error{Message: "cdddar: cdr of car of argument is nil"}
	}

	carCdrPair, ok := carPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdddar: cdr of car of argument is not a pair"}
	}

	if carCdrPair.Cdr == nil {
		return &Error{Message: "cdddar: cdr of cdr of car of argument is nil"}
	}

	carCdrCdrPair, ok := carCdrPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cdddar: cdr of cdr of car of argument is not a pair"}
	}

	return convertToObjObject(carCdrCdrPair.Cdr)
}

// Cddddr returns the cdr of the cdr of the cdr of the cdr of a pair
func Cddddr(args []obj.Object, env *obj.Environment) obj.Object {
	if len(args) != 1 {
		return &Error{Message: "cddddr requires exactly 1 argument"}
	}

	if args[0].Type() != obj.PAIR_OBJ {
		return &Error{Message: "cddddr argument must be a pair"}
	}

	pair := args[0].(*obj.PairObject)
	if pair.Cdr == nil {
		return &Error{Message: "cddddr: cdr of argument is nil"}
	}

	cdrPair, ok := pair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddddr: cdr of argument is not a pair"}
	}

	if cdrPair.Cdr == nil {
		return &Error{Message: "cddddr: cdr of cdr of argument is nil"}
	}

	cdrCdrPair, ok := cdrPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddddr: cdr of cdr of argument is not a pair"}
	}

	if cdrCdrPair.Cdr == nil {
		return &Error{Message: "cddddr: cdr of cdr of cdr of argument is nil"}
	}

	cdrCdrCdrPair, ok := cdrCdrPair.Cdr.(*obj.PairObject)
	if !ok {
		return &Error{Message: "cddddr: cdr of cdr of cdr of argument is not a pair"}
	}

	return convertToObjObject(cdrCdrCdrPair.Cdr)
}

// NullP returns #t if obj is an empty list, #f otherwise
func NullP(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the null? predicate according to R4RS
	// null? returns #t if obj is an empty list, and otherwise returns #f
	if len(args) != 1 {
		return &Error{Message: "null? requires exactly 1 argument"}
	}

	// In Scheme, both EMPTY_LIST and NULL_OBJECT represent empty lists
	return &obj.BooleanObject{Value: args[0].Type() == obj.EMPTYLIST_OBJ || args[0].Type() == obj.NULL_OBJ}
}

// ListP returns #t if obj is a list, #f otherwise
func ListP(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the list? predicate according to R4RS
	// list? returns #t if obj is a list, and otherwise returns #f
	if len(args) != 1 {
		return &Error{Message: "list? requires exactly 1 argument"}
	}

	// Check if the object is a proper list
	return &obj.BooleanObject{Value: isProperList(args[0])}
}

// isProperList checks if an object represents a proper list
func isProperList(object obj.Object) bool {
	// Empty list is a proper list
	if object.Type() == obj.EMPTYLIST_OBJ || object.Type() == obj.NULL_OBJ {
		return true
	}

	// If it's not a pair, it's not a proper list
	if object.Type() != obj.PAIR_OBJ {
		return false
	}

	// For pairs, we need to check if it's a proper list structure
	pair := object.(*obj.PairObject)

	// Traverse the list structure
	current := pair
	for {
		// If we reach an empty list, it's a proper list
		if current.Cdr == obj.EMPTY_LIST || current.Cdr == obj.NULL_OBJECT {
			return true
		}

		// If Cdr is not a pair, it's not a proper list (improper list)
		cdrPair, ok := current.Cdr.(*obj.PairObject)
		if !ok {
			return false
		}

		// Move to the next pair
		current = cdrPair
	}
}

// Length returns the length of a list
func Length(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the length procedure according to R4RS
	// length returns the length of list
	if len(args) != 1 {
		return &Error{Message: "length requires exactly 1 argument"}
	}

	// Check if the argument is a proper list
	if !isProperList(args[0]) {
		return &Error{Message: "length argument must be a list"}
	}

	// Handle empty list case
	if args[0].Type() == obj.EMPTYLIST_OBJ || args[0].Type() == obj.NULL_OBJ {
		return &obj.NumberObject{Value: num.Integer(0)}
	}

	// Count elements in the list
	count := 0
	current := args[0].(*obj.PairObject)
	for {
		count++
		// If we reach an empty list, we're done
		if current.Cdr == obj.EMPTY_LIST || current.Cdr == obj.NULL_OBJECT {
			break
		}
		// Move to the next pair
		current = current.Cdr.(*obj.PairObject)
	}

	return &obj.NumberObject{Value: num.Integer(int64(count))}
}

// Append appends lists together
func Append(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the append procedure according to R4RS
	// append returns a list consisting of the elements of the first list
	// followed by the elements of the other lists
	if len(args) == 0 {
		// With no arguments, return empty list
		return obj.EMPTY_LIST
	}

	if len(args) == 1 {
		// With one argument, check if it's a list and return it
		if args[0].Type() != obj.PAIR_OBJ && args[0].Type() != obj.EMPTYLIST_OBJ && args[0].Type() != obj.NULL_OBJ {
			return &Error{Message: "append arguments must be lists"}
		}
		return args[0]
	}

	// Check that all but the last argument are proper lists
	for i := 0; i < len(args)-1; i++ {
		if !isProperList(args[i]) {
			return &Error{Message: "append arguments must be proper lists"}
		}
	}

	// Handle case where all arguments are empty lists
	allEmpty := true
	for _, arg := range args {
		if arg.Type() != obj.EMPTYLIST_OBJ && arg.Type() != obj.NULL_OBJ {
			allEmpty = false
			break
		}
	}
	if allEmpty {
		return obj.EMPTY_LIST
	}

	// Build the result list
	var result obj.Object = obj.EMPTY_LIST

	// Process arguments in reverse order to build the list correctly
	for i := len(args) - 1; i >= 0; i-- {
		if args[i].Type() == obj.EMPTYLIST_OBJ || args[i].Type() == obj.NULL_OBJ {
			// Skip empty lists
			continue
		}

		if args[i].Type() != obj.PAIR_OBJ {
			return &Error{Message: "append arguments must be lists"}
		}

		// If this is the last argument (first in reverse order), just use it as is
		if i == len(args)-1 {
			result = args[i]
		} else {
			// For other arguments, we need to copy their elements
			elements := extractListElements(args[i])
			// Prepend these elements to the result
			for j := len(elements) - 1; j >= 0; j-- {
				result = &obj.PairObject{Car: elements[j], Cdr: result}
			}
		}
	}

	return result
}

// Reverse reverses a list
func Reverse(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the reverse procedure according to R4RS
	// reverse returns a newly allocated list consisting of the elements of list in reverse order
	if len(args) != 1 {
		return &Error{Message: "reverse requires exactly 1 argument"}
	}

	// Check if the argument is a proper list
	if !isProperList(args[0]) {
		return &Error{Message: "reverse argument must be a list"}
	}

	// Handle empty list case
	if args[0].Type() == obj.EMPTYLIST_OBJ || args[0].Type() == obj.NULL_OBJ {
		return obj.EMPTY_LIST
	}

	// Extract elements from the list
	elements := extractListElements(args[0])

	// Build reversed list
	var result obj.Object = obj.EMPTY_LIST
	for _, element := range elements {
		result = &obj.PairObject{Car: element, Cdr: result}
	}

	return result
}

// ListTail returns the kth tail of a list
func ListTail(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the list-tail procedure according to R4RS
	// list-tail returns the sub-list of list obtained by omitting the first k elements
	if len(args) != 2 {
		return &Error{Message: "list-tail requires exactly 2 arguments"}
	}

	// Second argument must be a number
	if args[1].Type() != obj.NUMBER_OBJ {
		return &Error{Message: "list-tail second argument must be a number"}
	}

	kObj := args[1].(*obj.NumberObject).Value
	kVal, ok := kObj.(num.Integer)
	if !ok {
		return &Error{Message: "list-tail second argument must be an integer"}
	}

	k := int(kVal.Value)
	if k < 0 {
		return &Error{Message: "list-tail second argument must be non-negative"}
	}

	// Check if the first argument is a proper list
	if !isProperList(args[0]) {
		return &Error{Message: "list-tail first argument must be a list"}
	}

	// Handle empty list case
	if args[0].Type() == obj.EMPTYLIST_OBJ || args[0].Type() == obj.NULL_OBJ {
		if k == 0 {
			return obj.EMPTY_LIST
		}
		return &Error{Message: "list-tail index out of bounds"}
	}

	// Traverse the list to find the kth tail
	current := args[0]
	for i := 0; i < k; i++ {
		// Check if we've reached the end of the list
		if current.Type() == obj.EMPTYLIST_OBJ || current.Type() == obj.NULL_OBJ {
			return &Error{Message: "list-tail index out of bounds"}
		}

		// Must be a pair at this point
		if current.Type() != obj.PAIR_OBJ {
			return &Error{Message: "list-tail first argument must be a list"}
		}

		pair := current.(*obj.PairObject)
		// Fix: Convert Cdr to obj.Object properly
		cdrObj, ok := pair.Cdr.(obj.Object)
		if !ok {
			// If Cdr is not already an obj.Object, convert it
			cdrObj = convertToObjObject(pair.Cdr)
		}
		current = cdrObj
	}

	return current
}

// ListRef returns the kth element of a list
func ListRef(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the list-ref procedure according to R4RS
	// list-ref returns the kth element of list
	if len(args) != 2 {
		return &Error{Message: "list-ref requires exactly 2 arguments"}
	}

	// Second argument must be a number
	if args[1].Type() != obj.NUMBER_OBJ {
		return &Error{Message: "list-ref second argument must be a number"}
	}

	kObj := args[1].(*obj.NumberObject).Value
	kVal, ok := kObj.(num.Integer)
	if !ok {
		return &Error{Message: "list-ref second argument must be an integer"}
	}

	k := int(kVal.Value)
	if k < 0 {
		return &Error{Message: "list-ref second argument must be non-negative"}
	}

	// Check if the first argument is a proper list
	if !isProperList(args[0]) {
		return &Error{Message: "list-ref first argument must be a list"}
	}

	// Handle empty list case
	if args[0].Type() == obj.EMPTYLIST_OBJ || args[0].Type() == obj.NULL_OBJ {
		return &Error{Message: "list-ref index out of bounds"}
	}

	// Traverse the list to find the kth element
	current := args[0].(*obj.PairObject)
	for i := 0; i < k; i++ {
		// Check if we've reached the end of the list
		if current.Cdr == obj.EMPTY_LIST || current.Cdr == obj.NULL_OBJECT {
			return &Error{Message: "list-ref index out of bounds"}
		}

		// Move to the next pair
		next, ok := current.Cdr.(*obj.PairObject)
		if !ok {
			return &Error{Message: "list-ref first argument must be a list"}
		}
		current = next
	}

	return convertToObjObject(current.Car)
}

// extractListElements extracts all elements from a list into a slice
func extractListElements(list obj.Object) []obj.Object {
	var elements []obj.Object

	// Handle empty list case
	if list.Type() == obj.EMPTYLIST_OBJ || list.Type() == obj.NULL_OBJ {
		return elements
	}

	// Extract elements from the list
	current := list.(*obj.PairObject)
	for {
		elements = append(elements, convertToObjObject(current.Car))

		// If we reach an empty list, we're done
		if current.Cdr == obj.EMPTY_LIST || current.Cdr == obj.NULL_OBJECT {
			break
		}

		// Move to the next pair
		next, ok := current.Cdr.(*obj.PairObject)
		if !ok {
			break
		}
		current = next
	}

	return elements
}

// Memq searches for obj in list using eq? comparison
func Memq(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the memq procedure according to R4RS
	// memq returns the first sublist of list whose car is obj
	// where the sublists of list are the non-empty lists
	if len(args) != 2 {
		return &Error{Message: "memq requires exactly 2 arguments"}
	}

	objToFind := args[0]

	// Second argument must be a list
	if !isProperList(args[1]) && args[1].Type() != obj.EMPTYLIST_OBJ && args[1].Type() != obj.NULL_OBJ {
		return &Error{Message: "memq second argument must be a list"}
	}

	// Handle empty list case
	if args[1].Type() == obj.EMPTYLIST_OBJ || args[1].Type() == obj.NULL_OBJ {
		return &obj.BooleanObject{Value: false}
	}

	// Search through the list
	current := args[1].(*obj.PairObject)
	for {
		// Check if current car matches obj using eq?
		eqResult := Eq([]obj.Object{objToFind, convertToObjObject(current.Car)}, env)
		if eqResult.Type() == obj.BOOLEAN_OBJ && eqResult.(*obj.BooleanObject).Value {
			// Found a match, return the current sublist
			return current
		}

		// If we reach an empty list, we're done
		if current.Cdr == obj.EMPTY_LIST || current.Cdr == obj.NULL_OBJECT {
			break
		}

		// Move to the next pair
		next, ok := current.Cdr.(*obj.PairObject)
		if !ok {
			break
		}
		current = next
	}

	// Not found
	return &obj.BooleanObject{Value: false}
}

// Memv searches for obj in list using eqv? comparison
func Memv(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the memv procedure according to R4RS
	// memv returns the first sublist of list whose car is obj
	// where the sublists of list are the non-empty lists
	if len(args) != 2 {
		return &Error{Message: "memv requires exactly 2 arguments"}
	}

	objToFind := args[0]

	// Second argument must be a list
	if !isProperList(args[1]) && args[1].Type() != obj.EMPTYLIST_OBJ && args[1].Type() != obj.NULL_OBJ {
		return &Error{Message: "memv second argument must be a list"}
	}

	// Handle empty list case
	if args[1].Type() == obj.EMPTYLIST_OBJ || args[1].Type() == obj.NULL_OBJ {
		return &obj.BooleanObject{Value: false}
	}

	// Search through the list
	current := args[1].(*obj.PairObject)
	for {
		// Check if current car matches obj using eqv?
		eqvResult := Eqv([]obj.Object{objToFind, convertToObjObject(current.Car)}, env)
		if eqvResult.Type() == obj.BOOLEAN_OBJ && eqvResult.(*obj.BooleanObject).Value {
			// Found a match, return the current sublist
			return current
		}

		// If we reach an empty list, we're done
		if current.Cdr == obj.EMPTY_LIST || current.Cdr == obj.NULL_OBJECT {
			break
		}

		// Move to the next pair
		next, ok := current.Cdr.(*obj.PairObject)
		if !ok {
			break
		}
		current = next
	}

	// Not found
	return &obj.BooleanObject{Value: false}
}

// Member searches for obj in list using equal? comparison
func Member(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the member procedure according to R4RS
	// member returns the first sublist of list whose car is obj
	// where the sublists of list are the non-empty lists
	if len(args) != 2 {
		return &Error{Message: "member requires exactly 2 arguments"}
	}

	objToFind := args[0]

	// Second argument must be a list
	if !isProperList(args[1]) && args[1].Type() != obj.EMPTYLIST_OBJ && args[1].Type() != obj.NULL_OBJ {
		return &Error{Message: "member second argument must be a list"}
	}

	// Handle empty list case
	if args[1].Type() == obj.EMPTYLIST_OBJ || args[1].Type() == obj.NULL_OBJ {
		return &obj.BooleanObject{Value: false}
	}

	// Search through the list
	current := args[1].(*obj.PairObject)
	for {
		// Check if current car matches obj using equal?
		equalResult := Equal([]obj.Object{objToFind, convertToObjObject(current.Car)}, env)
		if equalResult.Type() == obj.BOOLEAN_OBJ && equalResult.(*obj.BooleanObject).Value {
			// Found a match, return the current sublist
			return current
		}

		// If we reach an empty list, we're done
		if current.Cdr == obj.EMPTY_LIST || current.Cdr == obj.NULL_OBJECT {
			break
		}

		// Move to the next pair
		next, ok := current.Cdr.(*obj.PairObject)
		if !ok {
			break
		}
		current = next
	}

	// Not found
	return &obj.BooleanObject{Value: false}
}

// Assq searches for obj in association list using eq? comparison
func Assq(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the assq procedure according to R4RS
	// assq returns the first pair in alist whose car is obj
	if len(args) != 2 {
		return &Error{Message: "assq requires exactly 2 arguments"}
	}

	objToFind := args[0]

	// Second argument must be a list
	if !isProperList(args[1]) && args[1].Type() != obj.EMPTYLIST_OBJ && args[1].Type() != obj.NULL_OBJ {
		return &Error{Message: "assq second argument must be a list"}
	}

	// Handle empty list case
	if args[1].Type() == obj.EMPTYLIST_OBJ || args[1].Type() == obj.NULL_OBJ {
		return &obj.BooleanObject{Value: false}
	}

	// Search through the association list
	current := args[1].(*obj.PairObject)
	for {
		// Each element of the association list must be a pair
		if current.Car == nil {
			return &Error{Message: "assq: association list elements must be pairs"}
		}

		// Check if current element is a pair
		pair, ok := current.Car.(*obj.PairObject)
		if !ok {
			return &Error{Message: "assq: association list elements must be pairs"}
		}

		// Check if pair's car matches obj using eq?
		eqResult := Eq([]obj.Object{objToFind, convertToObjObject(pair.Car)}, env)
		if eqResult.Type() == obj.BOOLEAN_OBJ && eqResult.(*obj.BooleanObject).Value {
			// Found a match, return the pair
			return pair
		}

		// If we reach an empty list, we're done
		if current.Cdr == obj.EMPTY_LIST || current.Cdr == obj.NULL_OBJECT {
			break
		}

		// Move to the next pair
		next, ok := current.Cdr.(*obj.PairObject)
		if !ok {
			break
		}
		current = next
	}

	// Not found
	return &obj.BooleanObject{Value: false}
}

// Assv searches for obj in association list using eqv? comparison
func Assv(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the assv procedure according to R4RS
	// assv returns the first pair in alist whose car is obj
	if len(args) != 2 {
		return &Error{Message: "assv requires exactly 2 arguments"}
	}

	objToFind := args[0]

	// Second argument must be a list
	if !isProperList(args[1]) && args[1].Type() != obj.EMPTYLIST_OBJ && args[1].Type() != obj.NULL_OBJ {
		return &Error{Message: "assv second argument must be a list"}
	}

	// Handle empty list case
	if args[1].Type() == obj.EMPTYLIST_OBJ || args[1].Type() == obj.NULL_OBJ {
		return &obj.BooleanObject{Value: false}
	}

	// Search through the association list
	current := args[1].(*obj.PairObject)
	for {
		// Each element of the association list must be a pair
		if current.Car == nil {
			return &Error{Message: "assv: association list elements must be pairs"}
		}

		// Check if current element is a pair
		pair, ok := current.Car.(*obj.PairObject)
		if !ok {
			return &Error{Message: "assv: association list elements must be pairs"}
		}

		// Check if pair's car matches obj using eqv?
		eqvResult := Eqv([]obj.Object{objToFind, convertToObjObject(pair.Car)}, env)
		if eqvResult.Type() == obj.BOOLEAN_OBJ && eqvResult.(*obj.BooleanObject).Value {
			// Found a match, return the pair
			return pair
		}

		// If we reach an empty list, we're done
		if current.Cdr == obj.EMPTY_LIST || current.Cdr == obj.NULL_OBJECT {
			break
		}

		// Move to the next pair
		next, ok := current.Cdr.(*obj.PairObject)
		if !ok {
			break
		}
		current = next
	}

	// Not found
	return &obj.BooleanObject{Value: false}
}

// Assoc searches for obj in association list using equal? comparison
func Assoc(args []obj.Object, env *obj.Environment) obj.Object {
	// Implementing the assoc procedure according to R4RS
	// assoc returns the first pair in alist whose car is obj
	if len(args) != 2 {
		return &Error{Message: "assoc requires exactly 2 arguments"}
	}

	objToFind := args[0]

	// Second argument must be a list
	if !isProperList(args[1]) && args[1].Type() != obj.EMPTYLIST_OBJ && args[1].Type() != obj.NULL_OBJ {
		return &Error{Message: "assoc second argument must be a list"}
	}

	// Handle empty list case
	if args[1].Type() == obj.EMPTYLIST_OBJ || args[1].Type() == obj.NULL_OBJ {
		return &obj.BooleanObject{Value: false}
	}

	// Search through the association list
	current := args[1].(*obj.PairObject)
	for {
		// Each element of the association list must be a pair
		if current.Car == nil {
			return &Error{Message: "assoc: association list elements must be pairs"}
		}

		// Check if current element is a pair
		pair, ok := current.Car.(*obj.PairObject)
		if !ok {
			return &Error{Message: "assoc: association list elements must be pairs"}
		}

		// Check if pair's car matches obj using equal?
		equalResult := Equal([]obj.Object{objToFind, convertToObjObject(pair.Car)}, env)
		if equalResult.Type() == obj.BOOLEAN_OBJ && equalResult.(*obj.BooleanObject).Value {
			// Found a match, return the pair
			return pair
		}

		// If we reach an empty list, we're done
		if current.Cdr == obj.EMPTY_LIST || current.Cdr == obj.NULL_OBJECT {
			break
		}

		// Move to the next pair
		next, ok := current.Cdr.(*obj.PairObject)
		if !ok {
			break
		}
		current = next
	}

	// Not found
	return &obj.BooleanObject{Value: false}
}
